﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DWGdirect.DatabaseServices;
using DWGdirect.Geometry;


namespace FXnaCAD
{

    /// <summary>
    /// 要求支持逐层输出信息
    /// </summary>
    public class CADReader
    {

        /// <summary>
        /// 这里我们暂时支持DWG，回头继续支持DXF
        /// </summary>
        /// <param name="fname"></param>
        public void ReadCadFile(string fname,BaseWriter writer)
        {


           

            using (DWGdirect.Runtime.Services srv = new DWGdirect.Runtime.Services())
            {



              

                try
                {

                    using (Database db = new Database(false, false))
                    {

                        db.ReadDwgFile(fname, FileOpenMode.OpenForReadAndReadShare, true, "");

                        this.ConvertDBEntities(db,writer);


                    }

                 
                }


                catch (System.Exception e)
                {
                    throw e;
                }


             
            }

           
 
        }


        //存储可见图层

        List<string> normalLayers = new List<string>();
        List<string> unvisibleLayers = new List<string>();


      



        protected void ConvertDBEntities(Database db,BaseWriter writer)
        {

            //读取所有的图层属性，去掉不可见图层，专心读取可见图层，


            //读取并记录对应的不可见图层


           this.ReadOffLayers(db,normalLayers,unvisibleLayers);



            //初始化图层信息

           writer.InitLayers(normalLayers);




            //记录块参照信息防止重复炸开
            Dictionary<string, bool> ExplodedBR = new Dictionary<string, bool>();

           
            // db.CurrentSpaceId
            // db.CurrentViewportTableRecordId;

             ///循环读取所有基本图形
             ///

            //准备炸开图形BLOCK，这里我们不保证过深细节的块信息，
            //我个人认为那些信息不是很重要


            using (BlockTable pTable = (BlockTable)db.BlockTableId.GetObject(OpenMode.ForRead, false, true))
            {
                
               

                foreach (ObjectId id in pTable)
                {
                    using (BlockTableRecord pBlock = (BlockTableRecord)id.GetObject(OpenMode.ForRead, false, true))
                    {

                       

                        //开始判断是否是我们需要的model
                        if (pBlock.Name.ToUpper() == "*MODEL_SPACE")
                        {


                            List<ObjectId> lstBlockRef = new List<ObjectId>();
                           
                            
                            //查询所有的块参照


                            foreach (ObjectId item in pBlock)
                            {


                                if (item.IsNull || item.IsErased || !item.IsValid) continue;



                                Entity en = (Entity)item.GetObject(OpenMode.ForRead, false, true);
                                if (unvisibleLayers.Contains(en.Layer))
                                {
                                    continue;

                                }

                                
                              

                                BlockReference b= en as BlockReference;
                                if (b!=null)
                                {

                                    lstBlockRef.Add(item);
                                    
                                    
                                    
                                }


                                if (en != null && !en.IsDisposed)
                                    en.Dispose();



                            }



                            //循环并打碎
                            foreach (ObjectId item in lstBlockRef)
                            {


                                if (item.IsNull || item.IsErased || !item.IsValid) continue;


                                BlockReference br = (BlockReference)item.GetObject(OpenMode.ForWrite, false, true);

                                br.ExplodeToOwnerSpace();


                                if (br != null && !br.IsDisposed)
                                {
                                    br.Dispose();
                                    
                                }





                            }


                            //读取视图信息

                            //如果遇到块参照，则打碎

                            double[] param0 = new double[16];

                            ///当有单独的视图定义时
                            if (!db.CurrentViewportTableRecordId.IsNull)
                            {

                                using (ViewportTableRecord pRecord = (ViewportTableRecord)db.CurrentViewportTableRecordId.GetObject(OpenMode.ForRead))
                                {
                                    ///////////////////////////
                                    param0[0] = pRecord.Ucs.Xaxis.X;
                                    param0[1] = 0 - pRecord.Ucs.Yaxis.X;
                                    param0[2] = pRecord.Ucs.Zaxis.X;
                                    param0[3] = 0;

                                    param0[4] = 0 - pRecord.Ucs.Xaxis.Y;
                                    param0[5] = pRecord.Ucs.Yaxis.Y;
                                    param0[6] = pRecord.Ucs.Zaxis.Y;
                                    param0[7] = 0;

                                    param0[8] = pRecord.Ucs.Xaxis.Z;
                                    param0[9] = pRecord.Ucs.Yaxis.Z;
                                    param0[10] = pRecord.Ucs.Zaxis.Z;
                                    param0[11] = 0;

                                    param0[12] = 0;
                                    param0[13] = 0;
                                    param0[14] = 0;
                                    param0[15] = 1;
                                }

                            }
                            else
                            {
                                //没有时

                                ///////////////////////////
                                param0[0] = 1;
                                param0[1] = 0;
                                param0[2] = 0;
                                param0[3] = 0;

                                param0[4] = 0 ;
                                param0[5] =1;
                                param0[6] = 0;
                                param0[7] = 0;

                                param0[8] =0;
                                param0[9] = 0;
                                param0[10] = 1;
                                param0[11] = 0;

                                param0[12] = 0;
                                param0[13] = 0;
                                param0[14] = 0;
                                param0[15] = 1;

 
                            }

                           


                            //世界坐标系 到 视图坐标系
                            Matrix3d matrixVector = new Matrix3d(param0);




                            //之后就准备读入图形


                            foreach (ObjectId item in pBlock)
                            {


                                if (item.IsNull || item.IsErased || !item.IsValid) continue;

                                //测试，先不加视图转换，之后必须要改

                                this.ReadEntity(item,writer);



                            }



                        }




                    }
                }
            }




 
        }


        /// <summary>
        /// 读取文件库中所有的图层信息
        /// </summary>
        /// <param name="database"></param>
        /// <returns></returns>
        protected void  ReadOffLayers(Database database ,List<string> layers,List<string> unvisibleLayers)
        {
          
            //图层信息表格

            using (LayerTable pTable = (LayerTable)database.LayerTableId.GetObject(OpenMode.ForRead, false, true))
            {

                //如果未找到该信息，就返回

                if (pTable == null) return ;


                foreach (ObjectId id in pTable)
                {
                    if (id.IsNull || id.IsErased || !id.IsValid) continue;
                    using (LayerTableRecord pRecord = (LayerTableRecord)id.GetObject(OpenMode.ForRead, false, true))
                    {
                        if (pRecord.IsEraseStatusToggled || pRecord.IsErased || pRecord.IsOff || !pRecord.IsUsed || pRecord.IsHidden || pRecord.IsFrozen)//图层是否关闭
                        {
                          

                            unvisibleLayers.Add(pRecord.Name);

                            

                        }
                        else
                        {

                            layers.Add(pRecord.Name);
 

                        }


                        if (pRecord != null && !pRecord.IsDisposed)
                        {
                            pRecord.Dispose();
                        }
                    }
                }
                if (pTable != null && !pTable.IsDisposed)
                    pTable.Dispose();
            }
            

        }

        /// <summary>
        /// 读取基础图形样式表
        /// </summary>
        /// <param name="db"></param>
        protected void ReadSytles(Database db)
        {
          
 
        }


        protected void ReadEntity(ObjectId id,BaseWriter writer)
        {

            using (Entity pEnt = (Entity)id.Open(OpenMode.ForRead, false, true))
            {
                /**********************************************************************/
                /* Dump the entity                                                    */
                /**********************************************************************/

                    //判断单个图形的可见性
                    if (pEnt.Visible == false)
                    {
                        return;
                    }


                //如果在不可见图层

                    if (this.unvisibleLayers.Contains(pEnt.Layer))
                    {
                        return;
                        
                    }


                // Protocol extensions are not supported in DD.NET (as well as in ARX.NET)
                // so we just switch by entity type here
                // (maybe it makes sense to make a map: type -> delegate)
                switch (pEnt.GetRXClass().Name)
                {

                    case "AcDbArc":

                        writer.WriteEntity((Arc)pEnt);

                        break;
                    
                   
                    
                    case "AcDbCircle":
                        writer.WriteEntity((Circle)pEnt);
                        break;
                    case "AcDbPoint":
                        writer.WriteEntity((DBPoint)pEnt);
                        break;
                    case "AcDbText":
                        writer.WriteEntity((DBText)pEnt);
                        break;
                    
                    case "AcDbEllipse":
                        writer.WriteEntity((Ellipse)pEnt);
                        break;
                    
                    case "AcDbLine":

                        writer.WriteEntity((Line)pEnt);

                       
                        break;

                    case "AcDbMline":
                        //dump((Mline)pEnt, indent);
                        break;
                    case "AcDbMText":
                       // dump((MText)pEnt);
                        break;
                  
               
                    case "AcDbPolyline":
                        writer.WriteEntity((DWGdirect.DatabaseServices.Polyline)pEnt);
                        break;
                    case "AcDb2dPolyline":
                        //dump((Polyline2d)pEnt, indent);
                        break;



                    case "AcDbRay":
                        //dump((Ray)pEnt, indent);
                        break;
                 
                 
                
                 
                    case "AcDbSpline":
                       // pts = dump((Spline)pEnt);
                        break;



                }


            }
        }
             


    }
}
